package com.oneday.nuo.base.security.login;

import cn.hutool.core.util.StrUtil;
import com.anji.captcha.model.common.ResponseModel;
import com.anji.captcha.model.vo.CaptchaVO;
import com.anji.captcha.service.CaptchaService;
import com.oneday.nuo.base.common.RedisUtil;
import com.oneday.nuo.base.common.SpringUtil;
import com.oneday.nuo.base.dto.NuoAuthDTO;
import com.oneday.nuo.base.exception.LoginException;
import com.oneday.nuo.base.security.jwt.JwtUtil;
import com.oneday.nuo.base.security.password.NuoPasswordEncoder;
import com.oneday.nuo.base.security.user.NuoUser;
import com.oneday.nuo.base.security.user.NuoUserDetailsService;
import com.oneday.nuo.base.tactics.token.TokenContext;
import com.oneday.nuo.base.tactics.token.TokenTactics;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;


/**
 * 用户登录认证类
 * @Author: liushuai
 * @Date: 2021/2/9 19:40
 * @param : * @param null
 * @return :
 **/
@Slf4j
@Component
public class NuoAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private NuoUserDetailsService nuoUserDetailsService;
    @Autowired
    private NuoPasswordEncoder nuoPasswordEncoder;
    @Autowired
    private CaptchaService captchaService;

    @Value("${token.time-out}")
    private Long timeOut;

    @Value("${token.tokenType}")
    private String  tokenTactics;

    /**
     *验证码成功返回编号
     */
    private static final String V_CODE_SUCCESS = "0000";


    /**
     * 用户认证方法
     * @Author: liushuai
     * @Date: 2021/2/9 19:41
     * @param : * @param authentication
     * @return :org.springframework.security.core.Authentication
     **/
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        if(ObjectUtils.isEmpty(authentication.getPrincipal()) || ObjectUtils.isEmpty(authentication.getDetails()) || StrUtil.isBlank(authentication.getDetails().toString()) || StrUtil.isBlank(authentication.getPrincipal().toString())){
          throw  new LoginException("用户名或密码不能为空");
        }
        String userName = authentication.getPrincipal().toString();
        String password = authentication.getDetails().toString();
        NuoUser user =(NuoUser)authentication;
        ResponseModel verification = captchaService.verification(user.getCaptchaVO());
        if(!V_CODE_SUCCESS.equals(verification.getRepCode())){
            log.error(verification.getRepMsg());
            throw  new LoginException("验证码校验失败");
        }

        user = (NuoUser) nuoUserDetailsService.loadUserByUsername(userName);

        if(user == null){
            throw  new LoginException("用户名或密码错误");
        }
        boolean isPass = nuoPasswordEncoder.matches(password, user.getPassword());
        if(isPass){
            /**
             * 策略模式 非常nice
             **/
            TokenTactics tokenTacticsImpl = (TokenTactics)SpringUtil.getBean(tokenTactics);
            TokenContext tokenContext = new TokenContext( tokenTacticsImpl,user);
            tokenContext.setToken();
        }else{
            throw  new LoginException("用户名或密码错误");
        }
        return user;
    }
    /**
     *
     * @Author: liushuai
     * @Date: 2021/2/9 19:42
     * @param : * @param aClass
     * @return :boolean
     **/
    @Override
    public boolean supports(Class<?> aClass) {
        return aClass.equals(NuoUser.class);
    }
}
